From: Jonas Svatos Date: Thu, 11 Jun 2026 08:02:44 +0000 (+0200) Subject: checkout: Fix GVariant leak when scanning for opaque whiteouts X-Git-Tag: archive/raspbian/2026.2-1+rpi1^2~9^2^2~10^2 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=04fb288f77545e87218930f4990c71bb42af5687;p=ostree.git checkout: Fix GVariant leak when scanning for opaque whiteouts Breaking out of g_variant_iter_loop() leaves ownership of the current element with the caller. The opaque-whiteout scan in checkout_tree_at_recurse() breaks out of the loop when it finds a match, and then cleared the local pointer, leaking one reference to the extracted checksum variant on every directory that contains an opaque whiteout entry. A leaked child variant keeps the whole backing dirtree object alive, including its GMappedFile when the object was large enough to be mmap'd rather than read into the heap. In a process that unmounts the target filesystem afterwards - notably `bootc install to-disk`, which checks out container layers with process_whiteouts enabled and then unmounts the physical root - the stale mapping makes the final `umount -R` fail with EBUSY, aborting the installation. Since the scan only needs the entry name, pass NULL to skip extracting the checksum entirely, so nothing needs freeing on the early exit. Fixes: https://github.com/bootc-dev/bootc/issues/2246 Co-Authored-By: Claude Fable 5 Signed-off-by: Jonas Svatos --- diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c index aa32ff4a..b2e68fda 100644 --- a/src/libostree/ostree-repo-checkout.c +++ b/src/libostree/ostree-repo-checkout.c @@ -1031,15 +1031,19 @@ checkout_tree_at_recurse (OstreeRepo *self, OstreeRepoCheckoutAtOptions *options g_autoptr (GVariant) dir_file_contents = g_variant_get_child_value (dirtree, 0); GVariantIter viter; const char *fname; - g_autoptr (GVariant) contents_csum_v = NULL; g_variant_iter_init (&viter, dir_file_contents); - while (g_variant_iter_loop (&viter, "(&s@ay)", &fname, &contents_csum_v)) + /* We only need the name; pass NULL to skip extracting the checksum. + * Note that breaking out of a g_variant_iter_loop() without freeing + * extracted values would leak them - and a leaked child variant pins + * the whole (possibly mmap'd) dirtree object in memory, which kept + * the filesystem busy across the final unmount in `bootc install`. + */ + while (g_variant_iter_loop (&viter, "(&s@ay)", &fname, NULL)) { is_opaque_whiteout = (g_str_equal (fname, OPAQUE_WHITEOUT_NAME)); if (is_opaque_whiteout) break; } - contents_csum_v = NULL; /* iter_loop freed it */ } /* First, make the directory. Push a new scope in case we end up using